﻿using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using GalaSoft.MvvmLight.Command;
using Mss.Common.DomainObjects;
using Validation = Mss.Common.DomainObjects.Validation;

namespace Mss.UiCommon.Controls
{
    public class ValidationInfo : Control
    {
        #region Dependency Properties

        /// <summary>
        /// Using a DependencyProperty as the backing store for ErrorIconBrush.  
        /// This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty ErrorIconBrushProperty =
            DependencyProperty.Register("ErrorIconBrush", typeof(Brush), typeof(ValidationInfo),
                                        new UIPropertyMetadata(null));

        /// <summary>
        /// Using a DependencyProperty as the backing store for Validation.  
        /// This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty ValidationProperty =
            DependencyProperty.Register("Validation", typeof(Validation), typeof(ValidationInfo),
                                        new UIPropertyMetadata(null, onValidationPropertyChanged));

        /// <summary>
        /// Using a DependencyProperty as the backing store for PreviousErrorCommand.  
        /// This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty PreviousErrorCommandProperty =
            DependencyProperty.Register("PreviousErrorCommand", typeof(ICommand), typeof(ValidationInfo),
                                        new UIPropertyMetadata(null));

        /// <summary>
        /// Using a DependencyProperty as the backing store for NextErrorCommand.  
        /// This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty NextErrorCommandProperty =
            DependencyProperty.Register("NextErrorCommand", typeof(ICommand), typeof(ValidationInfo), 
                                        new UIPropertyMetadata(null));

        /// <summary>
        /// Using a DependencyProperty as the backing store for SelectedError.  
        /// This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty SelectedErrorProperty =
            DependencyProperty.Register("SelectedError", typeof(Error), typeof(ValidationInfo),
                                        new UIPropertyMetadata(null, onSelectedErrorPropertyChanged));

        /// <summary>
        /// Using a DependencyProperty as the backing store for CurrentIndex.  
        /// This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty CurrentIndexProperty =
            DependencyProperty.Register("CurrentIndex", typeof(int), typeof(ValidationInfo), 
                                        new UIPropertyMetadata(-1));


        #endregion

        #region Constructors

        static ValidationInfo()
        {
            //Apply default style.
            DefaultStyleKeyProperty.OverrideMetadata(typeof (ValidationInfo),
                                                     new FrameworkPropertyMetadata(typeof (ValidationInfo)));
        }

        public ValidationInfo()
        {
            PreviousErrorCommand = new RelayCommand(previousError, hasPreviousError);
            NextErrorCommand = new RelayCommand(nextError, hasNextError);

            Visibility = Visibility.Collapsed;
        }

        #endregion

        #region Properties

        [Category("Brushes")]
        public Brush ErrorIconBrush
        {
            get { return (Brush) GetValue(ErrorIconBrushProperty); }
            set { SetValue(ErrorIconBrushProperty, value); }
        }

        [Category("Common Properties")]
        public Validation Validation
        {
            get { return (Validation) GetValue(ValidationProperty); }
            set { SetValue(ValidationProperty, value); }
        }

        public ICommand PreviousErrorCommand
        {
            get { return (ICommand)GetValue(PreviousErrorCommandProperty); }
            private set { SetValue(PreviousErrorCommandProperty, value); }
        }

        public Error SelectedError
        {
            get { return (Error)GetValue(SelectedErrorProperty); }
            set { SetValue(SelectedErrorProperty, value); }
        }

        public ICommand NextErrorCommand
        {
            get { return (ICommand)GetValue(NextErrorCommandProperty); }
            private set { SetValue(NextErrorCommandProperty, value); }
        }

        public int CurrentIndex
        {
            get { return (int)GetValue(CurrentIndexProperty); }
            private set { SetValue(CurrentIndexProperty, value); }
        }

        #endregion

        #region Methods

        private static void onValidationPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = (ValidationInfo)d;
            var oldValue = (Validation) e.OldValue;
            var newValue = (Validation)e.NewValue;

            if (oldValue != null)
            {
                oldValue.Errors.CollectionChanged -= control.onErrorsCollectionChanged;    
            }

            if (newValue == null)
            {
                control.SelectedError = null;
                control.Visibility = Visibility.Collapsed;
                return;
            }

            control.SelectedError = newValue.Errors.FirstOrDefault();
            newValue.Errors.CollectionChanged += control.onErrorsCollectionChanged;    
        }

        private void onErrorsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            SelectedError = Validation.Errors.FirstOrDefault();
        }

        private static void onSelectedErrorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = (ValidationInfo) d;
            var newValue = (Error) e.NewValue;

            if (newValue == null || control.Validation == null || !control.Validation.Errors.Any())
            {
                control.CurrentIndex = -1;
                control.Visibility = Visibility.Collapsed;
                return;
            }

            control.Visibility = Visibility.Visible;
            control.CurrentIndex = control.Validation.Errors.IndexOf(newValue);
        }

        private void nextError()
        {
            SelectedError = Validation.Errors[CurrentIndex + 1];
        }

        private bool hasNextError()
        {
            if (Validation == null) return false;
            if (CurrentIndex == -1) return false;

            return CurrentIndex + 2 <= Validation.Errors.Count;
        }

        private void previousError()
        {
            SelectedError = Validation.Errors[CurrentIndex - 1];
        }

        private bool hasPreviousError()
        {
            if (Validation == null) return false;
            if (CurrentIndex == -1) return false;

            return CurrentIndex - 1 >= 0;
        }

        #endregion
    }
}